package com.lanzhou.yuanfen.security.session;

import com.lanzhou.yuanfen.security.MyUserDetails;
import com.lanzhou.yuanfen.security.SocialDetails;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @ClassName: {@link EnhanceSessionRegistryImpl}
 * @Description: 自定义会话注册器
 * @author: Lanzhou
 * @date: 2020/5/28 19:18
 * @QQ: 1627518680
 * @Copyright:2020 All rights reserved.
 */
@Component
public class EnhanceSessionRegistryImpl extends SessionRegistryImpl {

    /**
     * 获得用户Session信息
     *
     * @param user 用户信息
     */
    private List<SessionInformation> getSessionInformationList(UserDetails user) {
        // 获取父类会话注册器Session主体
        List<Object> users = this.getAllPrincipals();
        for (Object principal : users) {
            final UserDetails loggedUser = (UserDetails) principal;
            // 若有当前的: UserDetails 的唯一标识相等, 那就是判断为同一个用户返回
            if (user.getUsername().equals(loggedUser.getUsername())) {
                // 返回该用户全部Session信息
                return this.getAllSessions(principal, false);
            }
        }
        return null;
    }

    /**
     * 若存在用户已登录对当前登录用户下线: security 再配置中已经自动帮我们做了
     *
     * ConcurrentSessionControlAuthenticationStrategy.allowableSessionsExceeded
     * 会在新登入用户的时候调用onAuthentication, 从而判断系统默认配置一个用户可以使用多少个session,
     * 如果当前用户的Session多了, 那就会把多出的全部踢下线
     *
     * @param user      用户信息
     * @param sessionId sessionId 这个不会被下线其它全部下线
     */
    public void invalidateSession(UserDetails user, String sessionId) {
        List<SessionInformation> sessionsInfo = this.getSessionInformationList(user);
        if (sessionsInfo != null) {
            for (SessionInformation sessionInformation : sessionsInfo) {
                if (sessionId.equals(sessionInformation.getSessionId())) {
                    continue;
                }
                // 由于账户被顶自定义的全局Session在添加新的Session时会根据用户id覆盖之前的Session
                // 同时之前的Session被系统删除监听器会同步删除新添加的Session会导致全局Session信息丢失
                // 设置logout变量作为标记使全局Session删除时判断是否删除对应session
                Object principal = sessionInformation.getPrincipal();
                if (principal instanceof MyUserDetails) {
                    MyUserDetails oldUser = (MyUserDetails) sessionInformation.getPrincipal();
                    oldUser.setLogout(false);
                } else if (principal instanceof SocialDetails) {
                    SocialDetails oldUser = (SocialDetails) sessionInformation.getPrincipal();
                    oldUser.setLogout(false);
                }
                // 会话过期
                sessionInformation.expireNow();
            }
        }
    }

    /**
     * 参考示例代码
     * @param sessions
     * @param allowableSessions
     * @param registry
     * @throws SessionAuthenticationException
     */
    /*protected void allowableSessionsExceeded(List<SessionInformation> sessions,
                                             int allowableSessions, SessionRegistry registry)
            throws SessionAuthenticationException {
        if (exceptionIfMaximumExceeded || (sessions == null)) {
            throw new SessionAuthenticationException(messages.getMessage(
                    "ConcurrentSessionControlAuthenticationStrategy.exceededAllowed",
                    new Object[] { Integer.valueOf(allowableSessions) },
                    "Maximum sessions of {0} for this principal exceeded"));
        }

        // Determine least recently used sessions, and mark them for invalidation
        sessions.sort(Comparator.comparing(SessionInformation::getLastRequest));
        int maximumSessionsExceededBy = sessions.size() - allowableSessions + 1;
        List<SessionInformation> sessionsToBeExpired = sessions.subList(0, maximumSessionsExceededBy);
        for (SessionInformation session: sessionsToBeExpired) {
            session.expireNow();
        }
    }*/





}
